﻿using System.ComponentModel;
using System.IO;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Highlighting;
using Monti.Docking;
using Monti.MVVM.Services;
using Peter.Common;
using Peter.Interface;

namespace Peter.Logic
{
   /// <summary>
   /// Model for an editor item
   /// </summary>
   public class EditorViewModel : DockItem, IFileOperations, IClosable
   {
      private readonly EditorView m_View;
      private FileInfo m_FileInfo;

      /// <summary>
      /// Initializes a new editor object.
      /// </summary>
      public EditorViewModel ()
      {
         this.m_View = new EditorView { DataContext = this };
         this.Content = this.m_View;
         this.EditorOptionsChanged (null, null);
         MainViewModel.Options.EditorOptions.PropertyChanged += this.EditorOptionsChanged;
         MainViewModel.Options.Fonts.PropertyChanged += this.FontsChanged;
      }

      /// <summary>
      /// Gets or Sets the text in the editor.
      /// </summary>
      public string Text
      {
         get { return this.m_View._TextEditor.Text; }
         set
         {
            this.m_View._TextEditor.Text = value;
         }
      }

      /// <summary>
      /// Gets the file name of the editor.
      /// </summary>
      public new string Title
      {
         get { return (this.m_FileInfo == null) ? "New Document" : this.m_FileInfo.Name; }
      }

      /// <summary>
      /// Gets or Sets the file path.
      /// </summary>
      public string FilePath
      {
         get { return (this.m_FileInfo == null) ? string.Empty : this.m_FileInfo.FullName; }
         set
         {
            this.m_FileInfo = new FileInfo (value);
         }
      }

      /*/// <summary>
      /// Occurs when a property changes.
      /// </summary>
      /// <param name="sender">This object.</param>
      /// <param name="e">PropertyChangedEventArgs</param>
      private void OnPropertyChanged (object sender, PropertyChangedEventArgs e)
      {
         if (e.PropertyName == "IsActiveContent" && this.IsActiveContent)
         {
            MainViewModel.GuiDispatcher.BeginInvoke ((ThreadStart)(() =>
               Keyboard.Focus (this.m_View._TextEditor.TextArea)), DispatcherPriority.ContextIdle);
         }
      }*/

      /// <summary>
      /// Occurs when the application fonts change.
      /// </summary>
      /// <param name="sender">Font options.</param>
      /// <param name="e">PropertyChangedEventArgs</param>
      private void FontsChanged (object sender, PropertyChangedEventArgs e)
      {
         if (e.PropertyName == "EditorFontFamily" ||
             e.PropertyName == "EditorFontSize")
         {
            this.m_View._TextEditor.FontFamily = new FontFamily(MainViewModel.Options.Fonts.EditorFontFamily);
            this.m_View._TextEditor.FontSize = MainViewModel.Options.Fonts.EditorFontSize;
         }
      }

      /// <summary>
      /// Occurs when the editor options change.
      /// </summary>
      /// <param name="sender">Editor options.</param>
      /// <param name="e">PropertyChangedEventArgs</param>
      private void EditorOptionsChanged (object sender, PropertyChangedEventArgs e)
      {
         var options = MainViewModel.Options.EditorOptions;
         this.m_View._TextEditor.ShowLineNumbers = options.ShowLineNumbers;
         this.m_View._TextEditor.WordWrap = options.WrapText;
         this.m_View._TextEditor.Options.AllowScrollBelowDocument = options.AllowScrollPastDocument;
         this.m_View._TextEditor.Options.ConvertTabsToSpaces = options.ConvertTabsToSpaces;
         this.m_View._TextEditor.Options.EnableEmailHyperlinks = options.EnableEmails;
         this.m_View._TextEditor.Options.EnableHyperlinks = options.EnableHyperlinks;
         this.m_View._TextEditor.Options.IndentationSize = options.IndentSize;
         this.m_View._TextEditor.Options.RequireControlModifierForHyperlinkClick = options.HoldCtrlForHyperlinks;
         this.m_View._TextEditor.Options.ShowEndOfLine = options.ShowEol;
         this.m_View._TextEditor.Options.ShowSpaces = options.ShowSpaces;
         this.m_View._TextEditor.Options.ShowTabs = options.ShowTabs;
      }

      /// <summary>
      /// Sets the file data for the current file.
      /// </summary>
      /// <param name="filePath">Full path to file.</param>
      private void SetFile (string filePath)
      {
         this.FilePath = filePath;
         this.m_View._TextEditor.SyntaxHighlighting =
            HighlightingManager.Instance.GetDefinitionByExtension (this.m_FileInfo.Extension);
      }

      /// <summary>
      /// Opens the given file, return the dock content displaying the file.
      /// </summary>
      /// <param name="filePath">Full path to file to open.</param>
      /// <returns>Dock item displaying file.</returns>
      public void Open (string filePath)
      {
         this.SetFile (filePath);
         this.m_View._TextEditor.Load (this.m_FileInfo.FullName);
      }

      /// <summary>
      /// Checks to see if the save command can/needs to be invoked.
      /// </summary>
      /// <returns>True if save can/needs to be invoked, otherswise false.</returns>
      public bool CanSave ()
      {
         return true;
      }

      /// <summary>
      /// Saves the current data.
      /// </summary>
      public void Save ()
      {
         string filePath;
         if (string.IsNullOrEmpty (this.FilePath))
         {
            var saveService = ServiceManager.Resolve <ISaveFileService> ();
            if (saveService != null)
            {
               var result = saveService.ShowDialog ();
               if (!result) return;
               filePath = saveService.FileName;
               this.SetFile (filePath);
            }
            else
               return;
         }
         else
            filePath = this.FilePath;

         this.m_View._TextEditor.Save (filePath);
      }

      /// <summary>
      /// Gets if the item is ok to close.
      /// </summary>
      public bool OkToClose
      {
         get { return true; }
      }

      /// <summary>
      /// Called when the item is closing.
      /// </summary>
      public void Close ()
      {
         MainViewModel.Options.EditorOptions.PropertyChanged -= this.EditorOptionsChanged;
         MainViewModel.Options.Fonts.PropertyChanged -= this.FontsChanged;
      }

      /// <summary>
      /// Called when the item is closing.
      /// </summary>
      public override bool Closing ()
      {
         this.Close ();
         return true;
      }
   }
}
